Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

18장. Event Sourcing의 불변성과 보상 전략


이벤트는 왜 수정하면 안 되는가

Event Sourcing에서는
이벤트가 시스템의 기준 데이터(Source of Truth)다.

예를 들어 이런 기록이 있다고 하자.

PointEarned(10000)
PointSpent(3000)

이 기록은 “일어난 사실”이다.

  • 10,000 포인트가 적립되었고
  • 3,000 포인트가 사용되었다

이것은 과거의 사실이다.

Event Sourcing에서는

이미 발생한 사실을 나중에 수정하지 않는다.

이 원칙을 불변성(Immutable) 이라고 한다.


그런데 잘못 차감되었다면?

문제 상황을 보자.

PointEarned(10000)
PointSpent(3000)

그런데 알고 보니
3,000 포인트가 잘못 차감되었다.

상태 기반 시스템이라면 이렇게 할 수 있다.

balance = balance + 3000

하지만 Event Sourcing에서는
기존 이벤트를 수정하지 않는다.

대신 새로운 이벤트를 추가한다.

PointEarned(10000)
PointSpent(3000)
PointRefunded(3000)

과거를 지우지 않고
새로운 사실을 기록한다.

이것이 보상 이벤트(Compensating Event) 다.


왜 이렇게까지 해야 하는가

이 방식에는 중요한 의미가 있다.

  1. 모든 변경 이력이 남는다.
  2. 무엇이 잘못되었는지 추적 가능하다.
  3. 감사(Audit)와 분쟁 대응이 가능하다.

이벤트는 로그가 아니라
시스템의 공식 기록이기 때문이다.


이벤트 버전 관리란 무엇인가

여기서 또 하나의 질문이 생긴다.

이벤트 구조가 바뀌면 어떻게 하나?

예를 들어 처음에는 이벤트가 이랬다고 하자.

{
  "type": "PointEarned",
  "amount": 10000
}

나중에 정책이 바뀌어
적립 사유(reason)를 추가해야 한다.

{
  "type": "PointEarned",
  "amount": 10000,
  "reason": "promotion"
}

여기서 중요한 점은:

테이블을 두 개 만들지 않는다.
DDL을 매번 변경하지 않는다.

보통 Event Store는 이렇게 생긴다.

event_store
---------------------------------
id
aggregate_id
event_type
event_version
payload (JSON)
created_at

payload는 JSON이다.

구조가 바뀌면:

  • 기존 이벤트는 version = 1
  • 새 이벤트는 version = 2

로 저장한다.

테이블은 그대로 유지한다.


이벤트 삭제는 가능한가

원칙적으로는 삭제하지 않는다.

왜냐하면:

  • 삭제는 과거를 없애는 행위이기 때문이다.
  • Replay 시 상태가 달라질 수 있다.

다만 현실에서는 다음과 같은 경우가 있다.

  • 법적 삭제 요구(GDPR 등)
  • 민감 정보 제거 필요

이 경우에는:

  • 암호화
  • 마스킹
  • 이벤트 재작성(Migration)

같은 전략이 필요하다.

Event Sourcing은 단순한 기술 패턴이 아니라
운영 전략까지 포함한다.


순수 구조와 현실적인 구조

순수 Event Sourcing

  • balance 컬럼 없음
  • 항상 이벤트 기반 계산
  • Snapshot 사용

현실적 혼합 구조

  • 이벤트는 저장
  • balance 테이블도 유지
  • 이벤트 INSERT + balance UPDATE를 한 트랜잭션으로 처리

실무에서는 혼합 구조를 많이 사용한다.


정리

Event Sourcing에서 중요한 원칙은 세 가지다.

  1. 이벤트는 불변이다.
  2. 잘못된 처리는 보상 이벤트로 해결한다.
  3. 이벤트 버전 관리는 DDL 변경이 아니라 메시지 진화다.